package com.itbaizhan.dao.impl.impl;

import com.itbaizhan.common.JdbcDruidUtil;
import com.itbaizhan.common.JdbcUtils;
import com.itbaizhan.dao.impl.BaseDao;
import com.itbaizhan.exception.ApplicationException;
import org.apache.commons.beanutils.BeanUtils;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**通用接口实现类*/
//继承BaseDao 那么在UserDaoImpl也可以用BseDao方法，因为BaseDao变成父类
public class BaseDaoImpl implements BaseDao {
    /*通用DML操作方法*/
    @Override
    public int executeUpdate(String sql, Object[] param) {
        Connection connection = null;
        PreparedStatement ps = null;
        int row;
        try{
            connection = JdbcUtils.getConnection();
            ps = connection.prepareStatement(sql);
            //得到参数的个数
            //不知道有多小个参数，通过ParameterMetaData下的getParameterCount()返回个数，
            // prepareStatement下的getParameterMetaData()得到ParameterMetaData
            ParameterMetaData pd = ps.getParameterMetaData();
            for(int i=0;i<pd.getParameterCount();i++){
                //setObject可以返回所有类型
                ps.setObject(i+1,param[i]);

            }
            row = ps.executeUpdate();

        }catch (Exception e){
            e.printStackTrace();
            throw new ApplicationException(e.getMessage());
        }finally {
            JdbcUtils.closeResource(ps,connection);
        }
        return row;
    }

    @Override
    public <T> List<T> select(String sql, Object[] param, Class<T> clazz) {
        Connection connection = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        List<T> list = new ArrayList<>();
        try{
            connection = JdbcUtils.getConnection();
            ps = connection.prepareStatement(sql);
            //得到参数的个数
            ParameterMetaData pm = ps.getParameterMetaData();
            for(int i =0;i<pm.getParameterCount();i++){
                ps.setObject(i+1,param[i]);
            }
            rs = ps.executeQuery();
            //获取结果集信息，返回多小列
            /*在prepareStatement对象下有getMetaData()方法，返回ResultSetMetaData，
            * 在ResultSetMetaData下的getColumnCount(),从而得到列的多小*/
            ResultSetMetaData rm = rs.getMetaData();
            while(rs.next()){
                //ORM映射
                //通过反射实例化实体类对象
                T bean = clazz.newInstance();
                //实体类的属性名必须要和表的列名相同
                for(int i=0;i<rm.getColumnCount();i++){
                    //得到列名 getColumnName()根据列的序号获取列名
                    String columnName = rm.getColumnName(i+1);
                    //获取列的值
                    Object value = rs.getObject(columnName);
                    //通过BeanUtil 工具类将值映射到对象中
                    //添加两个Jar包，commons-beanutils-1.9.4.jar与commons-logging-1.2.jar
                    /*通过列名取得值，（表的列名必须与实体类的的列名一样），再将值映射到bean类中*/
                    BeanUtils.setProperty(bean,columnName,value);
                }
                list.add(bean);
            }
        }catch (Exception e){
            e.printStackTrace();
            throw new ApplicationException(e.getMessage());
        }finally {
            JdbcDruidUtil.closeResource(rs,ps,connection);
        }

        return list;
    }
}
